package com.ruoyi.system.protocol.impl;

import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.SysDictType;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysClasses;
import com.ruoyi.system.domain.SysCommonDataProperty;
import com.ruoyi.system.domain.SysDataProperty;
import com.ruoyi.system.domain.SysDataType;
import com.ruoyi.system.protocol.IDynamicCacheService;
import com.ruoyi.system.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class DynamicCacheServiceImpl implements IDynamicCacheService {

    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicCacheServiceImpl.class);


    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysCommonDataPropertyService sysCommonDataPropertyService;

    @Autowired
    private ISysDataPropertyService sysDataPropertyService;

    @Autowired
    private ISysClassesService sysClassesService;

    @Autowired
    private ISysDataTypeService sysDataTypeService;

    @Autowired
    private ISysDictTypeService sysDictTypeService;

    @Autowired
    private ISysDictDataService sysDictDataService;

    @PostConstruct
    public void init() {
        long start = System.currentTimeMillis();
        LOGGER.info("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓初始化缓存开始↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
        refreshClassesListByCache();
        refreshCommonDataPropertyListCache();
        refreshDataTypeListByCache();
        refreshDictDataListByCache();
        refreshDictTypeListByCache();
        refreshFieldForwardAndReverse();
        refreshDataPropertyListCache(null);
        long end = System.currentTimeMillis();
        LOGGER.info("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑初始化缓存结束耗时:["+(end-start)+"]↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
    }


    @Override
    public List<SysCommonDataProperty> getCommonDataPropertyListCache() {
        String key = "common.dpList";
        if(redisCache.exists(key)){
            return redisCache.getCacheList(key);
        }else{
            return refreshCommonDataPropertyListCache();
        }
    }

    @Override
    public List<SysCommonDataProperty> refreshCommonDataPropertyListCache() {
        String key = "common.dpList";
        List<SysCommonDataProperty> commonDataPropertyList = sysCommonDataPropertyService.selectSysCommonDataPropertyList(null);
        for (SysCommonDataProperty sysCommonDataProperty : commonDataPropertyList) {
            SysDataType sysDataType = sysDataTypeService.selectSysDataTypeById(sysCommonDataProperty.getDataTypeId());
            String searchField = getDynamicField(sysDataType.getRetrievalType(),
                    sysCommonDataProperty.getIndexed(),
                    sysCommonDataProperty.getParticiple(),
                    sysCommonDataProperty.getMultiValued(),
                    sysCommonDataProperty.getStored()) + sysCommonDataProperty.getNameEn();
            sysCommonDataProperty.setSearchNameEn(searchField);
            sysCommonDataProperty.setDataTypeName(sysDataType.getFormType());
        }
        redisCache.deleteObject(key);
        redisCache.setCacheList(key, commonDataPropertyList);
        return commonDataPropertyList;
    }

    @Override
    public List<SysDataProperty> getDataPropertyListCache(String classesEn) {
        String key = "private.dpList";
        SysClasses sysClasses = null;
        List<SysDataProperty> filterDataProperty = new ArrayList<>();
        if(org.apache.commons.lang3.StringUtils.isNotBlank(classesEn) && !"null".equals(classesEn)){
            List<SysClasses> classesListByCache = getClassesListByCache();
            sysClasses = classesListByCache.stream().filter(x -> Objects.equals(x.getNameEn(), classesEn)).findFirst().orElse(null);
        }
        if(sysClasses == null){
            return redisCache.getCacheList(key);
        }
        if(redisCache.exists(key)){
            List<SysDataProperty> cacheList = redisCache.getCacheList(key);
            Long classesId = sysClasses.getId();
            filterDataProperty = cacheList.stream().filter(x -> Objects.equals(x.getClassesId(), classesId)).collect(Collectors.toList());
            return filterDataProperty;
        }else{
            return refreshDataPropertyListCache(classesEn);
        }
    }

    @Override
    public List<SysDataProperty> refreshDataPropertyListCache(String classesEn) {
        String key = "private.dpList";
        SysClasses sysClasses = null;
        List<SysDataProperty> filterDataProperty = new ArrayList<>();
        if(org.apache.commons.lang3.StringUtils.isNotBlank(classesEn) && !"null".equals(classesEn)){
            List<SysClasses> classesListByCache = getClassesListByCache();
            sysClasses = classesListByCache.stream().filter(x -> Objects.equals(x.getNameEn(), classesEn)).findFirst().orElse(null);
        }
        List<SysDataProperty> sysDataPropertyList = sysDataPropertyService.selectSysDataPropertyList(null);
        for (SysDataProperty sysDataProperty : sysDataPropertyList) {
            SysDataType sysDataType = sysDataTypeService.selectSysDataTypeById(sysDataProperty.getDataTypeId());
            SysClasses querySysClasses = sysClassesService.selectSysClassesById(sysDataProperty.getClassesId());
            String searchField = getDynamicField(sysDataType.getRetrievalType(),
                    sysDataProperty.getIndexed(),
                    sysDataProperty.getParticiple(),
                    sysDataProperty.getMultiValued(),
                    sysDataProperty.getStored()) + sysDataProperty.getNameEn();
            sysDataProperty.setSearchNameEn(searchField);
            sysDataProperty.setDataTypeName(sysDataType.getFormType());
            sysDataProperty.setClassesEn(querySysClasses.getNameEn());
        }
        redisCache.deleteObject(key);
        redisCache.setCacheList(key, sysDataPropertyList);
        if(sysClasses == null){
            return sysDataPropertyList;
        }
        Long classesId = sysClasses.getId();
        filterDataProperty = sysDataPropertyList.stream().filter(x -> Objects.equals(x.getClassesId(), classesId)).collect(Collectors.toList());
        return filterDataProperty;
    }

    @Override
    public String getFiledForward(String fieldName) {
        String key = "field.forward.Map";
        Map<String, Object> cacheMap = redisCache.getCacheMap(key);
        if(!cacheMap.containsKey(fieldName)){
           return fieldName;
        }
        String cacheMapValue = redisCache.getCacheMapValue(key, fieldName)+"";
        if(StringUtils.isNotEmpty(cacheMapValue) && !"null".equals(cacheMapValue)){
            return cacheMapValue;
        }
        return fieldName;
    }

    @Override
    public String getFiledReverse(String fieldName) {
        String key = "field.revers.Map";
        Map<String, Object> cacheMap = redisCache.getCacheMap(key);
        if(!cacheMap.containsKey(fieldName)){
            return fieldName;
        }
        String cacheMapValue = redisCache.getCacheMapValue(key, fieldName)+"";
        if(StringUtils.isNotEmpty(cacheMapValue) && !"null".equals(cacheMapValue)){
            return cacheMapValue;
        }
        return fieldName;
    }

    @Override
    public String getFiledForwardOrReverse(String fieldName) {
        String key = "field.all.Map";
        Map<String, Object> cacheMap = redisCache.getCacheMap(key);
        if(!cacheMap.containsKey(fieldName)){
            return fieldName;
        }
        String cacheMapValue = redisCache.getCacheMapValue(key, fieldName)+"";
        if(StringUtils.isNotEmpty(cacheMapValue) && !"null".equals(cacheMapValue)){
            return cacheMapValue;
        }
        return fieldName;
    }

    @Override
    public void refreshFieldForwardAndReverse() {
        String forwardKey = "field.forward.Map";
        String reverseKey = "field.revers.Map";
        String allKey = "field.all.Map";
        HashMap<String, String> forwardMap = new HashMap<>();
        HashMap<String, String> reverseMap = new HashMap<>();
        HashMap<String, String> allMap = new HashMap<>();

        List<SysCommonDataProperty> commonDataPropertyList = sysCommonDataPropertyService.selectSysCommonDataPropertyList(null);
        for (SysCommonDataProperty dataProperty : commonDataPropertyList) {
            SysDataType sysDataType = sysDataTypeService.selectSysDataTypeById(dataProperty.getDataTypeId());
            String nameEn = dataProperty.getNameEn();
            String searchNameEn = getDynamicField(sysDataType.getRetrievalType(),
                    dataProperty.getIndexed(),
                    dataProperty.getParticiple(),
                    dataProperty.getMultiValued(),
                    dataProperty.getStored()) + dataProperty.getNameEn();
            forwardMap.put(nameEn, searchNameEn);
            reverseMap.put(searchNameEn, nameEn);
        }
        List<SysDataProperty> sysDataPropertyList = sysDataPropertyService.selectSysDataPropertyList(null);
        for (SysDataProperty sysDataProperty : sysDataPropertyList) {
            SysDataType sysDataType = sysDataTypeService.selectSysDataTypeById(sysDataProperty.getDataTypeId());
            String nameEn = sysDataProperty.getNameEn();
            String searchNameEn = getDynamicField(sysDataType.getRetrievalType(),
                    sysDataProperty.getIndexed(),
                    sysDataProperty.getParticiple(),
                    sysDataProperty.getMultiValued(),
                    sysDataProperty.getStored()) + sysDataProperty.getNameEn();
            if(!forwardMap.containsKey(nameEn)){
                forwardMap.put(nameEn, searchNameEn);
            }
            if(!reverseMap.containsKey(searchNameEn)){
                reverseMap.put(searchNameEn, nameEn);
            }
        }
        allMap.putAll(forwardMap);
        allMap.putAll(reverseMap);
        redisCache.deleteObject(forwardKey);
        redisCache.deleteObject(reverseKey);
        redisCache.deleteObject(allKey);
        redisCache.setCacheMap(forwardKey, forwardMap);
        redisCache.setCacheMap(reverseKey, reverseMap);
        redisCache.setCacheMap(allKey, allMap);
    }

    @Override
    public List<SysClasses> getClassesListByCache() {
        String key = "classesList";
        if(redisCache.exists(key)){
            return redisCache.getCacheList(key);
        }else{
            return refreshClassesListByCache();
        }
    }

    @Override
    public SysClasses findClassesByCache(Long id) {
        List<SysClasses> classesListByCache = getClassesListByCache();
        SysClasses sysClasses = classesListByCache.stream().filter(x -> id.equals(x.getId())).findFirst().orElse(null);
        return sysClasses;
    }

    @Override
    public List<SysClasses> refreshClassesListByCache() {
        String key = "classesList";
        List<SysClasses> sysClassesList = sysClassesService.selectSysClassesList(null);
        for (SysClasses sysClasses : sysClassesList) {
            String db = sysClasses.getDb();
            String business_db = sysDictDataService.selectDictLabel("business_db", db);
            sysClasses.setDbZh(business_db);
        }
        redisCache.deleteObject(key);
        redisCache.setCacheList(key, sysClassesList);
        return sysClassesList;
    }

    @Override
    public List<SysDataType> getDataTypeListByCache() {
        String key = "dataTypeList";
        if(redisCache.exists(key)){
            return redisCache.getCacheList(key);
        }else{
            return refreshDataTypeListByCache();
        }
    }

    @Override
    public SysDataType findDataTypeByCache(Long id) {
        List<SysDataType> dataTypeListByCache = getDataTypeListByCache();
        SysDataType sysDataType = dataTypeListByCache.stream().filter(x -> id.equals(x.getId())).findFirst().orElse(null);
        return sysDataType;
    }

    @Override
    public List<SysDataType> refreshDataTypeListByCache() {
        String key = "dataTypeList";
        List<SysDataType> sysDataTypeList = sysDataTypeService.selectSysDataTypeList(null);
        redisCache.deleteObject(key);
        redisCache.setCacheList(key, sysDataTypeList);
        return sysDataTypeList;
    }

    @Override
    public List<SysDictType> getDictTypeListByCache() {
        String key = "dictTypeList";
        if(redisCache.exists(key)){
            return redisCache.getCacheList(key);
        }else{
            return refreshDictTypeListByCache();
        }
    }

    @Override
    public SysDictType findDictTypeByCache(Long id) {
        List<SysDictType> dictTypeListByCache = getDictTypeListByCache();
        SysDictType sysDictType = dictTypeListByCache.stream().filter(x -> id.equals(x.getDictId())).findFirst().orElse(null);
        return sysDictType;
    }

    @Override
    public List<SysDictType> refreshDictTypeListByCache() {
        String key = "dictTypeList";
        List<SysDictType> sysDictTypes = sysDictTypeService.selectDictTypeAll();
        for (SysDictType sysDictType : sysDictTypes) {
            List<SysDictData> sysDictData = sysDictTypeService.selectDictDataByType(sysDictType.getDictType());
            sysDictType.setDictDataList(sysDictData);
        }
        redisCache.deleteObject(key);
        redisCache.setCacheList(key, sysDictTypes);
        return sysDictTypes;
    }

    @Override
    public List<SysDictData> getDictDataListByCache() {
        String key = "dictDataList";
        if(redisCache.exists(key)){
            return redisCache.getCacheList(key);
        }else{
            return refreshDictDataListByCache();
        }
    }

    @Override
    public List<SysDictData> getDictDataListByCache(String dictType) {
        List<SysDictType> dictTypeListByCache = getDictTypeListByCache();
        SysDictType sysDictType = dictTypeListByCache.stream().filter(x -> dictType.equals(x.getDictType())).findFirst().orElseGet(() -> new SysDictType());
        return sysDictType.getDictDataList();
    }

    @Override
    public List<SysDictData> getDictDataByCache(String dictType, String dictValue) {
        List<SysDictData> dictDataListByCache = getDictDataListByCache(dictType);
        if(dictDataListByCache != null && dictDataListByCache.size() > 0){
            return dictDataListByCache.stream().filter(x-> dictValue.equals(x.getDictValue())).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public SysDictData findDictDataByCache(Long id) {
        List<SysDictData> dictDataListByCache = getDictDataListByCache();
        SysDictData sysDictData = dictDataListByCache.stream().filter(x -> id.equals(x.getDictCode())).findFirst().orElse(null);
        return sysDictData;
    }



    @Override
    public List<SysDictData> refreshDictDataListByCache() {
        String key = "dictDataList";
        List<SysDictData> sysDictData = sysDictDataService.selectDictDataList(null);
        redisCache.deleteObject(key);
        redisCache.setCacheList(key, sysDictData);
        return sysDictData;
    }

    /**
     * @param dataType 检索类型
     * @param indexed  是否索引
     * @param multiLanguage 分词
     * @param multiValued 是否多值
     * @param stored  是否存储
     * @return
     */
    public static String getDynamicField(String dataType, String indexed, String multiLanguage,  String multiValued, String stored) {
        String fieldStr = "";
        fieldStr += dataType;
        if ("1".equals(indexed)) {
            fieldStr += "I";
        }
        if ("1".equals(multiLanguage)) {
            fieldStr += "T";
        }
        if ("1".equals(multiValued)) {
            fieldStr += "M";
        }
        if ("1".equals(stored)) {
            fieldStr += "S";
        }
        fieldStr += "_";
        return fieldStr;
    }

}
